package com.hqyj.javaSpringBoot.aop;

import com.hqyj.javaSpringBoot.filter.ParamFilter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/*
* 打印控制器request信息
* 打印指定方法调用执行时间
* */
@Aspect//@Aspect:作用是把当前类标识为一个切面供容器读取
@Component//注册为系统bean
public class MyAop {
    private final static Logger LOGGER = LoggerFactory.getLogger(MyAop.class);


    /**
     * -关联在方法上的切点，大面积额切入,支持与或非逻辑运算符
     * -第一个 * 代表返回类型不限
     * -第二个 * 代表 module 下所有子包
     * -第三个 * 代表所有类
     * -第四个 * 代表所有方法
     * (..) 代表参数不限
     * Order 代表优先级，数字越小优先级越高
     */
    @Pointcut("execution(public * com.hqyj.javaSpringBoot.modules.*.controller.*.*(..))")
    @Order(value=1)//优先级 越小越高
    public void controllerJoinPoint(){}

    //自定义注解精确切点  @annotation表示标注了某个注解的所有方法。
    @Pointcut("@annotation(com.hqyj.javaSpringBoot.aop.MethodCallTimeAnnotation)")
    @Order(value = 1)
    public void methodCallTimeJoinPoint(){}

    //控制器切面通知
    @Before(value="controllerJoinPoint()")//在后面参数值之后执行
    public void beforeController  (JoinPoint joinPoint){
        LOGGER.debug("==== before Controller ====");
    }

    @Around(value="controllerJoinPoint()")
    public Object aroundController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        LOGGER.debug("======== Around Controller ========");
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//获取request对象
        HttpServletRequest request = requestAttributes.getRequest();
        LOGGER.debug(String.format("RemoteAddr: %s", request.getRemoteAddr()));
        LOGGER.debug(String.format("RequestURI: %s", request.getRequestURI()));
        LOGGER.debug(String.format("RequestMethod: %s", request.getMethod()));
        LOGGER.debug(String.format("Class: %s", proceedingJoinPoint.getTarget().getClass()));
        LOGGER.debug(String.format("Signature: %s",
                proceedingJoinPoint.getSignature().getName()));
        LOGGER.debug(String.format("Args: %s", proceedingJoinPoint.getArgs() == null ? "" :
                proceedingJoinPoint.getArgs()));
        return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());//执行切进去目标的方法
    }

    @After(value="controllerJoinPoint()")
    public void afterController  (JoinPoint joinPoint){
        LOGGER.debug("==== after Controller ====");
    }


    //注解切面通知
    @Around(value="methodCallTimeJoinPoint()")
    public Object aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        LOGGER.debug("======== Around Annotation ========");
        long start = System.currentTimeMillis();//获取系统当前时间
        Object obj = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        long end = System.currentTimeMillis();
        LOGGER.debug(String.format("Call method time: %s ms.", (end - start)));
        return obj;
    }
}
